#ifndef BLOCKWISE_INTEGRATED_INDEX_HELPER
#define BLOCKWISE_INTEGRATED_INDEX_HELPER

#include "meshTypes.hpp"

namespace hms::swe
{

struct IndexHelper {
	struct _Mesh {
		Index nx;
		Index ny;
		static constexpr Index ng {1};
		Index nxg;
		Index nyg;

		static constexpr Index nOuterLayers {2};
		Index nxInner;
		Index nyInner;
	};
	_Mesh mesh;

	struct _BlockSizes {
		Index sizeX;
		Index sizeY;
		Index nFullX;
		Index nFullY;
		Index remSizeX;
		Index remSizeY;
	};
	_BlockSizes blocks;

	struct _BlockBegs {
		Index mesh; // = ng
		Index blocks; // = ng + nOuterLayers
		Index remX;
		Index remY;
		Index outerX;
		Index outerY;
	};
	_BlockBegs beg;
};

template<typename MeshType>
IndexHelper indexHelper(
	Index sizeX,
	Index sizeY,
	const StructMeshBase<MeshType>& mesh
){
	IndexHelper helper;
	auto& m { helper.mesh };

	static constexpr Index ng {1};
	Index
		nx { mesh.nCellsX() },
		ny { mesh.nCellsY() },
		nxg { nx + 2*ng };

	m.nx = nx;
	m.ny = ny;
	m.nxg = nxg;
	m.nyg = ny + 2*ng;

	/* outer two domain cell layers partially use central scheme
	 * that's why 2*2 cells are deducted */
	// m.nOuterLayers = 2;
	m.nxInner = nx - 2*m.nOuterLayers;
	m.nyInner = ny - 2*m.nOuterLayers;

	auto& b { helper.blocks };
	b.sizeX = sizeX;
	b.sizeY = sizeY;
	b.nFullX   = m.nxInner / sizeX;
	b.nFullY   = m.nyInner / sizeY;
	b.remSizeX = m.nxInner % sizeX;
	b.remSizeY = m.nyInner % sizeY;

	auto& beg { helper.beg };
	beg.mesh = ng;
	beg.blocks = ng + m.nOuterLayers;
	beg.remX = beg.blocks + b.nFullX * sizeX;
	beg.remY = beg.blocks + b.nFullY * sizeY;
	beg.outerX = beg.blocks + m.nxInner;
	beg.outerY = beg.blocks + m.nyInner;

	return helper;
}

}

#endif